package com.cskaoyan.javase.oop1._6constructor;

/**
 * 构造器(非常重要的地位)
 * 创建一个教师类，有课程和年龄两个属性，行为是可以上课。
 * 现在我们需要创建以下对象：
 * 18岁的Java老师对象
 * 28岁的C++老师对象
 * 30岁的Python老师对象
 * ...
 * 按照之前我们的做法，需要先创建出对象，再进行成员变量的赋值。
 * 这样做如果只有一个两个对象还好，如果需要创建很多对象，就有点过于麻烦了。
 * 对象的属性，能不能"出厂"的时候就设定好呢？
 * 有这种需求时，就需要，构造方法（constructor，也叫构造器）来完成了。
 *
 * 构造方法也是方法
 * 但属于一种特殊的方法，具有以下特点：
 * 语法结构和一般方法不同，如下：
 * [访问权限修饰符] 类名(形参列表){
 *   // 构造方法体
 * }
 *
 * 注：
 *      1.访问权限修饰符我们还没有学习，这里我们默认它是public修饰的。
 *      当然,访问权限修饰符是可以为空的,可以不写.
 *      2.类名的位置必须和当前类的类名完全一致。（类名是大驼峰的，这里也要大驼峰）
 *      这里的"类名"可以认为是构造器的名字
 *      构造器的名字要和类名保持一致.
 *      千万不要认为"类名"是构造器的返回值类型
 *      构造器没有返回值,不需要返回值
 *      所以构造器当中是不能使用return的
 *
 *      3.形参列表可以为空，称之为无参构造方法，简称无参构造。当然也可以有参数，是为有参构造。
 *      4.构造方法体，和一般方法类似，可以写语句,也属于局部位置。
 *
 * 构造器的作用:
 *      在Java中使用new关键字，创建对象，必然调用构造方法。构造器的作用是在new对象过程中,用来给成员变量赋值的。
 *      补充:
 *      1.new对象的时候，JVM自动去调用这个方法，构造方法无法通过普通方法的调用方式调用。
 *      在堆上创建对象是JVM完成的,整个过程程序员是不参与的,构造器方法是JVM调用的,程序员没有办法主动调用构造器.
 *      但是我们可以在写new对象语法时,告诉JVM,调用哪个构造方法,来完成创建对象,去给成员变量赋值.
 *      语法:
 *      new 类名(实参);
 *      根据实参的不同,调用不同的构造器
 *
 *      2.构造器的作用不是创建对象，创建对象是JVM的事情。构造器充其量是告诉JVM在创建对象过程中，给成员变量赋什么值。
 *
 *      构造器的定义:
 *      1.(重点)在Java中,如果一个类没有手动提供任何一个构造器,那么编译器在编译该类时,就会给该类加上无参构造器,也叫做"默认构造器,默认无参"
 *      格式如下:
 *      [访问权限修饰符] 类名(){}
 *
 *      2.默认无参是不能进行赋值的,如果希望手动赋值,那就给类添加上有参构造
 *      构造器的方法体中同样隐含了this传参,指向当前对象
 *      语法格式:
 *      [访问权限修饰符] 类名(数据类型 成员变量名...){
 *          this.成员变量名 = 成员变量名;
 *      }
 *
 *      3.同一个类中可以定义多个构造器,它们之间是方法重载的关系.
 *      4.构造器的定义格式十分固定,可以使用IDEA快捷键直接生成,建议大家以后定义构造器,如无特殊需求都使用快捷键.我们把快捷键自动生成的构造器,称之为"标准格式构造器"
 *      快捷键: 在类体空白处 按 alt + insert
 *      标准格式构造器:
 *      [访问权限修饰符] 类名(){}
 *      [访问权限修饰符] 类名(数据类型 成员变量名...){
 *     this.成员变量名 = 成员变量名;
 * }
 *     5.(补充,了解)
 *     构造器放在成员变量和成员方法之间定义
 *
 *      注意事项:
 *      1.要注意类中多个构造器方法是重载的关系,典型的比如形参不同,是无法构成方法重载的
 *      2.如果类中提供了任何一个构造器(也包含无参构造)
 *      那么就不会提供默认无参了
 *      推论:
 *          a.在Java中,任何类都有构造器
 *          b.建议在定义类时,顺手给出该类的无参构造(快捷键自动生成)
 *      3.构造器中同样隐含this传参,这个this同样可以访问类中的成员变量和方法.(和成员方法一样)
 *      4.构造器的作用是new对象过程中,给对象的成员变量赋值,它的作用和创建对象没有任何关系.
 *      5.(重点)使用构造器,给成员变量赋值,它的结果一定是准确的.给构造器传的参数,就是该成员变量的最终取值.
 *      这是因为构造器的赋值,在new对象过程中,是最后执行的,你可以永远相信构造器
 *
 * @since 09:31
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 18岁的Java老师对象,这里调用Teacher类的无参构造器
        Teacher t = new Teacher();
        t.course = "Java";
        t.age = 18;
        t.teach();
        // 28岁的C++老师对象,这里调用Teacher类的无参构造器
        Teacher t2 = new Teacher();
        t2.course = "C++";
        t2.age = 28;
        t2.teach();

        System.out.println("------------------");
        Teacher t3 = new Teacher("数学");
        System.out.println(t3.course);

        Teacher t4 = new Teacher("Python", 28);
        System.out.println(t4.age);
        System.out.println(t4.course);
    }

    // 该方法会返回一个Teacher对象
    public static Teacher test() {
        // return null;
        Teacher t = new Teacher();
        String str = "123";
        String st2 = new String("123");
        return t;
    }
}
class A{
    // int num;
    // public A(int num) {
    //     this.num = num;
    // }
}
class Teacher {
    String course;
    String name;
    int age;

    public Teacher(String course, String name, int age) {
        this.course = course;
        this.name = name;
        this.age = age;
    }

    public Teacher() {
    }

    public Teacher(String course, int age) {
        this.course = course;
        this.age = age;
    }

    public Teacher(String course) {
        this.course = course;
    }
    // public Teacher(String name) {
    //     this.name = name;
    // }

    public Teacher(int age) {
        this.age = age;
        this.teach();
    }

    public void teach() {
        System.out.println(age + "岁的" + course + "老师,正在上课!");
    }

    /*// 默认无参构造器
    public Teacher() {
    }

    // 定义单参构造器给course赋值
    public Teacher(String course) {
        this.course = course;
    }

    // 定义双参构造器给course,age赋值
    public Teacher(String course, int age) {
        this.course = course;
        this.age = age;
    }*/
}